

#include <stdlib.h>
#include "crow_all.h"
#include "CppSQLite3U.h"

const unsigned char g_blankPng[1246] = {
    0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,
    0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x08,0x06,0x00,0x00,0x00,0x5C,0x72,0xA8,
    0x66,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x16,0x25,0x00,0x00,0x16,
    0x25,0x01,0x49,0x52,0x24,0xF0,0x00,0x00,0x04,0x90,0x49,0x44,0x41,0x54,0x78,0x5E,
    0xED,0xD0,0x31,0x01,0x00,0x00,0x00,0xC2,0xA0,0xF5,0x4F,0xED,0x6B,0x08,0x88,0x40,
    0x61,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,
    0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,
    0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,
    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,
    0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,
    0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,
    0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,
    0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,
    0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,
    0x80,0x01,0x03,0x06,0x0C,0x18,0x30,0xF0,0x03,0x03,0x01,0x3C,0x00,0x01,0xBE,0xB2,
    0xDD,0xE5,0x00,0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
};

std::string GetXmlFromDb(const std::string &a, const std::string &b)
{
    std::string s;
    try
    {
        char szT[4096];
        sprintf(szT, "%s.mbtiles", a.c_str());
        CppSQLite3DB db;
        db.open(szT);
        db.setBusyTimeout(100);
        sprintf(szT, "select value from metadata where name='%s.xml'", b.c_str());
        CppSQLite3Query qry = db.execQuery(szT);
        if (!qry.eof())
        {
            qry >> szT;
            s = szT;
        }
        db.close();
    }
    catch (CppSQLite3Exception& p)
    {
    }

    if (s.length() <= 10)
    {
        s = "404: Can't find ";
        s += b;
        s += ".xml.";
    }
    return s;
}

int GetImageFromDb(std::string &s, const std::string &a, int x, int y, int z)
{
    try
    {
        typedef std::map<std::string, CppSQLite3Statement> MapStmt;
        static MapStmt mapStmt;
        auto it = mapStmt.find(a);
        if (it == mapStmt.end())
        {
            char szT[128];
            sprintf(szT, "%s.mbtiles", a.c_str());
            CppSQLite3DB db;
            db.open(szT);
            db.setBusyTimeout(100);
            it = mapStmt.insert(std::make_pair(a, db.compileStatement("select tile_data from tiles where zoom_level=? and tile_column=? and tile_row=?"))).first;
        }

        if (it != mapStmt.end())
        {
            it->second.reset();
            it->second.bind(1, z);
            it->second.bind(2, x);
            it->second.bind(3, y);
            CppSQLite3Query qry = it->second.execQuery();
            if (!qry.eof())
            {
                qry >> s;
            }
        }
    }
    catch (CppSQLite3Exception& p)
    {
    }

    return s.size();
}

int main(int argc, char **argv)
{
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")
        ([]()
    {
        const char *pT = "/metadata/a :get metadata info from a.mbtiles\n" \
            "/a/b.xml :get a.mbtiles/b.xml\n" \
            "/a/z/x/y.png :get a.mbtiles/z/x/y.png\n" \
            "/a/z/x/y.jpg :get a.mbtiles/z/x/y.jpg\n";
        return pT;
    });

    CROW_ROUTE(app, "/metadata/<string>")
        ([](const std::string &a)
    {
        crow::json::wvalue v;
        try
        {
            char szN[64];
            char szT[4096];
            sprintf(szT, "%s.mbtiles", a.c_str());
            CppSQLite3DB db;
            db.open(szT);
            db.setBusyTimeout(100);
            sprintf(szT, "select name, value from metadata");
            CppSQLite3Query qry = db.execQuery(szT);
            while (!qry.eof())
            {
                qry >> szN >> szT;
                v[szN] = szT;
            }
            db.close();
        }
        catch (CppSQLite3Exception& p)
        {
        }
        if (v.keys().size() < 1)
        {
            v["name"] = "cache";
            v["version"] = "1.0.0";
            v["type"] = "overlay";
            v["description"] = "some info here";
            v["format"] = "png";
            v["bounds"] = "-180,-85.0511,180,85.0511";
        }

        return v;
    });

    CROW_ROUTE(app, "/<string>/<string>.xml")
        ([](const std::string &a, const std::string &b)
    {
        crow::response res;
        res.set_header("Context-Type", "text/xml");
        res.set_header("Access-Control-Allow-Origin", "*");
        //res.set_header("Access-Control-Allow-Credentials", "true");
        res.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT,PATCH, HEAD");
        res.set_header("Access-Control-Allow-Headers", "token,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,XRequested-With");
        res.body = GetXmlFromDb(a, b);
        return res;
    });

    // crow 2024.5.29发布的1.2.0版本还是无法解析类似“/<string>/v2/<string>.json”的URL
    // CROW_ROUTE(app, "/<string>/v2/<string>.json")
    //     ([](const std::string &a, const std::string &b)
    // {
    //     crow::json::wvalue v;
    //     v["first"] = a;
    //     v["second"] = b;
    // 
    //     return v;
    // });

    CROW_ROUTE(app, "/<string>/<int>/<int>/<int>.png")
        ([](const std::string &a, int z, int x, int y)
    {
        crow::response res;
        res.set_header("Context-Type", "image/png");
        res.set_header("Access-Control-Allow-Origin", "*");
        //res.set_header("Access-Control-Allow-Credentials", "true");
        res.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT,PATCH, HEAD");
        res.set_header("Access-Control-Allow-Headers", "token,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,XRequested-With");
        GetImageFromDb(res.body, a, x, y, z);
        return res;
    });

    CROW_ROUTE(app, "/<string>/<int>/<int>/<int>.jpg")
        ([](const std::string &a, int z, int x, int y)
    {
        crow::response res;
        res.set_header("Context-Type", "image/jpeg");
        res.set_header("Access-Control-Allow-Origin", "*");
        //res.set_header("Access-Control-Allow-Credentials", "true");
        res.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT,PATCH, HEAD");
        res.set_header("Access-Control-Allow-Headers", "token,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,XRequested-With");
        GetImageFromDb(res.body, a, x, y, z);
        return res;
    });

    int nPort = 1111;
    FILE *fp = fopen("mbtilesSrv.txt", "rt");
    if (fp != NULL)
    {
        fscanf(fp, "%d", &nPort);
        fclose(fp);
    }
    if (argc > 1)
    {
        nPort = atoi(argv[1]);
    }
    app.port(nPort).run();

    return 0;
}